package fun.ticsmyc.rpc.client.transport.netty;

import fun.ticsmyc.rpc.Config;
import fun.ticsmyc.rpc.client.transport.RpcClient;
import fun.ticsmyc.rpc.common.entity.RpcRequest;
import fun.ticsmyc.rpc.common.entity.TRPCServiceProperties;
import fun.ticsmyc.rpc.nacos.registry.ServiceDiscovery;
import fun.ticsmyc.rpc.nacos.registry.impl.NacosServiceDiscoveryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * 基于Netty的客户端
 * 客户端应当是单例的，对应一个全局唯一的RpcRequestSenderFactory
 *
 * @author Ticsmyc
 * @date 2020-10-23 21:03
 */
public class NettyRpcClient implements RpcClient {

    private static final Logger logger = LoggerFactory.getLogger(NettyRpcClient.class);

    private static ServiceDiscovery serviceDiscovery;

    private static volatile NettyRpcClient INSTANCE;
    private NettyRpcClient(){}
    public static NettyRpcClient getInstance(){
        if(INSTANCE == null){
            synchronized (NettyRpcClient.class){
                if(INSTANCE == null){
                    INSTANCE = new NettyRpcClient();
                    init();
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public Object sendRequest(RpcRequest rpcRequest,TRPCServiceProperties trpcServiceProperties) {
        //如果请求发送失败，可能是因为服务端下线，而nacos存在延迟，导致拿到了过期的地址。
        //所以每次重连前要先拉取一下服务提供者的地址
        for(int i=1;i<=MAX_RETRY_COUNT;++i){
            try{
                InetSocketAddress inetSocketAddress = serviceDiscovery.lookupService(trpcServiceProperties.getSignature(),i);
                RpcRequestSender rpcRequestSender =RpcRequestSenderFactory.getRpcRequestSender(inetSocketAddress);
                return rpcRequestSender.sendAndGetReturnValue(rpcRequest);
            }catch (Exception e) {
                logger.error("连接服务端失败，尝试重连 "+i+"/"+MAX_RETRY_COUNT+" : {}",e.getMessage());
            }
        }
        logger.error("rpc请求发送失败");
        return null;
    }

    //初始化整个系统
    public static void init(){
        serviceDiscovery = new NacosServiceDiscoveryImpl(Config.getLoadBalancer());
        RpcRequestSenderFactory.init(Config.getSerializer());
    }
}
